using System;
using System.IO;
using System.Diagnostics;
using System.Threading;
using Nito.HashAlgorithms;
using System.Collections.Generic;
using System.IO.Ports;
using System.Runtime.InteropServices;
using DidaManager.Log;
using System.Text;

namespace DidaManager.Native.SerialPort
{
    public enum InitialCrcValue { Zeros, NonZero1 = 0xffff, NonZero2 = 0x1D0F }

    // 添加串口工作模式枚举
    public enum SerialPortMode
    {
        Command,    // 普通命令模式
        YmodemWait, // Ymodem等待模式（等待设备响应）
        YmodemTransfer // Ymodem传输模式（文件传输中）
    }

    public class Ymodem
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern nint CreateFile(string lpFileName, FileAccess dwDesiredAccess, uint dwShareMode,
                             nint lpSecurityAttributes, FileMode dwCreationDisposition, uint dwFlagsAndAttributes, nint hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(nint hObject);

        /*
         * Upload file via Ymodem protocol to the device
         * ret: is the transfer succeeded? true is if yes
         */
        private string path = string.Empty;
        public string Path{get {return path;} set { path = value; } }
        private string portName = string.Empty;
        public string PortName { get { return portName; } set { portName = value; } }
        private string dataBits = string.Empty;
        public string DataBits { get { return dataBits; } set { dataBits = value; } }
        private string stopBits = string.Empty;
        public string StopBits { get { return stopBits; } set { stopBits = value; } }
        private string parity = string.Empty;
        public string Parity { get { return parity; } set { parity = value; } }
        public int BaudRate { get { return baudRate; } set { baudRate = value; } }
        private int baudRate = 115200;

        private System.IO.Ports.SerialPort serialPort = new System.IO.Ports.SerialPort();
        public event EventHandler? NowDownloadProgressEvent = null;
        public event EventHandler? DownloadResultEvent = null;
        private const ushort recvBufferLength = 1024 * 2;
        private byte[] recvBuffer = new byte[recvBufferLength];
        private List<byte> buffer = new List<byte>();//串口发送buf
        
        // 改进的状态管理
        private SerialPortMode _currentMode = SerialPortMode.Command;
        private readonly object _modeLock = new object();
        private Queue<byte> _ymodemDataQueue = new Queue<byte>(); // Ymodem数据队列
        private readonly object _queueLock = new object();
        
        // 命令模式的数据缓冲
        private StringBuilder _commandBuffer = new StringBuilder(); // 命令模式字符串缓冲区
        private readonly object _commandBufferLock = new object();
        private List<string> _commandLines = new List<string>(); // 完整的命令行列表
        private readonly object _commandLinesLock = new object();

        public static bool IsSerialPortUsed(string portName)
        {
            bool result = false;
            try
            {
                nint handle = CreateFile(@"\\.\" + portName, FileAccess.ReadWrite, 0, nint.Zero, FileMode.Open, 0, nint.Zero);
                if (handle != nint.Zero && handle.ToInt32() != -1)
                {
                    result = false;
                    CloseHandle(handle);
                }
                else
                {
                    result = true;
                }
            }
            catch
            {
                result = true;
            }
            return result;
        }

        public void SetSerialPort(System.IO.Ports.SerialPort serialPort)
        {
            this.serialPort = serialPort;
        }

        // 设置串口工作模式
        public void SetMode(SerialPortMode mode)
        {
            lock (_modeLock)
            {
                _currentMode = mode;
                LogManager.Debug($"Serial port mode changed to: {mode}");
                
                // 切换到Ymodem模式时清空队列和缓冲区
                if (mode == SerialPortMode.YmodemWait || mode == SerialPortMode.YmodemTransfer)
                {
                    lock (_queueLock)
                    {
                        _ymodemDataQueue.Clear();
                    }
                    lock (_commandBufferLock)
                    {
                        _commandBuffer.Clear();
                    }
                    lock (_commandLinesLock)
                    {
                        _commandLines.Clear();
                    }
                    // 清空串口缓冲区
                    if (serialPort.IsOpen)
                    {
                        serialPort.DiscardInBuffer();
                        serialPort.DiscardOutBuffer();
                    }
                }
                // 切换到命令模式时清空Ymodem队列
                else if (mode == SerialPortMode.Command)
                {
                    lock (_queueLock)
                    {
                        _ymodemDataQueue.Clear();
                    }
                }
            }
        }

        // 获取当前工作模式
        public SerialPortMode GetCurrentMode()
        {
            lock (_modeLock)
            {
                return _currentMode;
            }
        }

        // 从命令行缓冲区读取一行数据（带超时）
        private string ReadCommandLine(int timeoutMs = 5000)
        {
            int startTime = Environment.TickCount;
            
            while (Environment.TickCount - startTime < timeoutMs)
            {
                lock (_commandLinesLock)
                {
                    if (_commandLines.Count > 0)
                    {
                        string line = _commandLines[0];
                        _commandLines.RemoveAt(0);
                        LogManager.Debug($"ReadCommandLine: {line}");
                        return line;
                    }
                }
                Thread.Sleep(10); // 短暂等待
            }
            
            LogManager.Debug("ReadCommandLine timeout");
            return string.Empty;
        }

        // 从命令缓冲区读取原始数据（不按行分割）
        private string ReadCommandData(int timeoutMs = 5000)
        {
            int startTime = Environment.TickCount;
            string result = "";
            
            while (Environment.TickCount - startTime < timeoutMs)
            {
                lock (_commandLinesLock)
                {
                    if (_commandLines.Count > 0)
                    {
                        // 有完整的行，返回第一行
                        result = _commandLines[0];
                        _commandLines.RemoveAt(0);
                        LogManager.Debug($"ReadCommandData (line): {result}");
                        return result;
                    }
                }
                
                // 检查缓冲区中是否有部分数据
                lock (_commandBufferLock)
                {
                    if (_commandBuffer.Length > 0)
                    {
                        result = _commandBuffer.ToString();
                        _commandBuffer.Clear();
                        LogManager.Debug($"ReadCommandData (buffer): {result}");
                        return result;
                    }
                }
                
                Thread.Sleep(10); // 短暂等待
            }
            
            LogManager.Debug("ReadCommandData timeout");
            return result;
        }

        public bool SendCMD(string cmd,string replyCheck,int checkCycle,bool bNewLine=false)
        {
            if(0==cmd.Length||0==replyCheck.Length)
            {
                return false;
            }
            if(checkCycle==0)
            {
                checkCycle = 1;
            }
            
            // 确保在命令模式下
            SetMode(SerialPortMode.Command);
            
            LogManager.Debug($"SendCMD: {cmd.Replace("\r", "\\r").Replace("\n", "\\n")} -> expect: {replyCheck}");

            byte[] byteArray = System.Text.Encoding.Default.GetBytes(cmd);
            SendData(byteArray);
            
            string data = "";
            bool bRet = false;
            
            for (int i = 0; i < checkCycle; i++)
            {
                try
                {
                    if (bNewLine)
                    {
                        // 按行读取（等待\r\n结尾的完整行）
                        data = ReadCommandLine(5000);
                        if (data == null)
                        {
                            LogManager.Debug($"SendCMD cycle {i+1}: ReadCommandLine timeout");
                            continue;
                        }
                        LogManager.Debug($"SendCMD cycle {i+1} (line): {data}");
                    }
                    else
                    {
                        // 读取原始数据（可能包含部分数据）
                        string newData = ReadCommandData(5000);
                        if (string.IsNullOrEmpty(newData))
                        {
                            LogManager.Debug($"SendCMD cycle {i+1}: ReadCommandData timeout");
                            continue;
                        }
                        data += newData;
                        LogManager.Debug($"SendCMD cycle {i+1} (data): {newData}, total: {data}");
                    }

                    Console.WriteLine(data);
                    
                    if (data.Contains(replyCheck))
                    {
                        LogManager.Debug($"SendCMD success: found '{replyCheck}' in '{data}'");
                        bRet = true;
                        break;
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Error($"SendCMD exception: {ex.Message}");
                    bRet = false;
                }
            }

            LogManager.Debug($"SendCMD result: {bRet}");
            return bRet;
        }

        public bool CheckCMD(string replyCheck, int checkCycle, bool bNewLine = false)
        {
            if (0 == replyCheck.Length)
            {
                return false;
            }
            if (checkCycle == 0)
            {
                checkCycle = 1;
            }
            
            // 确保在命令模式下
            SetMode(SerialPortMode.Command);
            
            LogManager.Debug($"CheckCMD: expect '{replyCheck}'");

            string data = "";
            bool bRet = false;
            
            for (int i = 0; i < checkCycle; i++)
            {
                try
                {
                    if (bNewLine)
                    {
                        // 按行读取（等待\r\n结尾的完整行）
                        data = ReadCommandLine(5000);
                        if (data == null)
                        {
                            LogManager.Debug($"CheckCMD cycle {i+1}: ReadCommandLine timeout");
                            continue;
                        }
                        LogManager.Debug($"CheckCMD cycle {i+1} (line): {data}");
                    }
                    else
                    {
                        // 读取原始数据（可能包含部分数据）
                        string newData = ReadCommandData(5000);
                        if (string.IsNullOrEmpty(newData))
                        {
                            LogManager.Debug($"CheckCMD cycle {i+1}: ReadCommandData timeout");
                            continue;
                        }
                        data += newData;
                        LogManager.Debug($"CheckCMD cycle {i+1} (data): {newData}, total: {data}");
                    }

                    Console.WriteLine(data);
                    
                    if (data.Contains(replyCheck))
                    {
                        LogManager.Debug($"CheckCMD success: found '{replyCheck}' in '{data}'");
                        bRet = true;
                        break;
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Error($"CheckCMD exception: {ex.Message}");
                    bRet = false;
                }
            }

            LogManager.Debug($"CheckCMD result: {bRet}");
            return bRet;
        }

        // 示例：如何在同一个接收函数中处理不同模式的数据
        public void DemonstrateUsage()
        {
            LogManager.Debug("=== 演示串口模式切换 ===");
            
            // 1. 命令模式：发送AT命令，期望接收\r\n结尾的响应
            LogManager.Debug("1. 命令模式演示");
            SetMode(SerialPortMode.Command);
            bool cmdResult = SendCMD("AT+INFO\r\n", "AT+INFO+OK", 3, true); // bNewLine=true，按行读取
            LogManager.Debug($"命令模式结果: {cmdResult}");
            
            // 2. 准备进入Ymodem模式：发送准备命令
            LogManager.Debug("2. 准备进入Ymodem模式");
            bool prepareResult = SendCMD("AT+RZ=firmware.bin\r\n", "C", 10, false); // 等待单个'C'字符
            LogManager.Debug($"准备结果: {prepareResult}");
            
            // 3. Ymodem模式：处理单字节数据
            if (prepareResult)
            {
                LogManager.Debug("3. 进入Ymodem传输模式");
                SetMode(SerialPortMode.YmodemTransfer);
                
                // 在Ymodem模式下，GetSerialPortReadByte会从队列中读取单个字节
                byte receivedByte = 0;
                GetSerialPortReadByte(ref receivedByte);
                LogManager.Debug($"Ymodem模式接收字节: {receivedByte} (0x{receivedByte:X2})");
                
                // 传输完成后自动切换回命令模式
                SetMode(SerialPortMode.Command);
            }
            
            // 4. 回到命令模式：发送结束命令
            LogManager.Debug("4. 回到命令模式");
            bool endResult = SendCMD("AT+DBG=1\r\n", "AT+DBG+OK", 3, true);
            LogManager.Debug($"结束命令结果: {endResult}");
            
            LogManager.Debug("=== 演示完成 ===");
        }

        public bool SerialClose()
        {
            try
            {
                LogManager.Debug("=== Starting SerialClose ===");
                
                if (serialPort.IsOpen)
                {
                    SerialPortMode currentMode = GetCurrentMode();
                    LogManager.Debug($"Current mode before closing: {currentMode}");
                    
                    // 根据当前模式执行相应的停止操作
                    switch (currentMode)
                    {
                        case SerialPortMode.YmodemWait:
                        case SerialPortMode.YmodemTransfer:
                            LogManager.Debug("Stopping Ymodem transfer...");
                            // 清空Ymodem数据队列
                            lock (_queueLock)
                            {
                                _ymodemDataQueue.Clear();
                                LogManager.Debug("Ymodem data queue cleared");
                            }
                            // 触发传输失败事件
                            DownloadResultEvent?.Invoke(false, new EventArgs());
                            LogManager.Debug("Ymodem transfer stopped due to port closure");
                            break;
                            
                        case SerialPortMode.Command:
                            LogManager.Debug("Stopping command mode operations...");
                            // 清空命令缓冲区
                            lock (_commandBufferLock)
                            {
                                _commandBuffer.Clear();
                                LogManager.Debug("Command buffer cleared");
                            }
                            lock (_commandLinesLock)
                            {
                                _commandLines.Clear();
                                LogManager.Debug("Command lines cleared");
                            }
                            break;
                    }
                    
                    // 强制切换到命令模式（停止所有操作）
                    SetMode(SerialPortMode.Command);
                    
                    // 清空串口缓冲区
                    try
                    {
                        serialPort.DiscardInBuffer();
                        serialPort.DiscardOutBuffer();
                        LogManager.Debug("Serial port buffers discarded");
                    }
                    catch (Exception bufferEx)
                    {
                        LogManager.Error($"Error discarding buffers: {bufferEx.Message}");
                    }
                    
                    // 取消事件订阅
                    serialPort.DataReceived -= SerialPort_DataReceived;
                    LogManager.Debug("DataReceived event unsubscribed");
                    
                    // 关闭串口
                    serialPort.Close();
                    LogManager.Debug("Serial port closed successfully");
                }
                else
                {
                    LogManager.Debug("Serial port was already closed");
                }
                
                // 最终清理所有缓冲区和队列
                lock (_queueLock)
                {
                    _ymodemDataQueue.Clear();
                }
                lock (_commandBufferLock)
                {
                    _commandBuffer.Clear();
                }
                lock (_commandLinesLock)
                {
                    _commandLines.Clear();
                }
                
                LogManager.Debug($"=== SerialClose completed, IsOpen: {serialPort.IsOpen} ===");
                return !serialPort.IsOpen;
            }
            catch (Exception ex)
            {
                LogManager.Error($"Error closing serial port: {ex.Message}");
                LogManager.Error($"Stack trace: {ex.StackTrace}");
                return false;
            }
        }

        public void YModemBegin()
        {
            // 确保在Ymodem模式下才能开始发送
            if (GetCurrentMode() == SerialPortMode.YmodemTransfer)
            {
                // 如果已经在传输中，则不重复开始
                return;
            }
            SetMode(SerialPortMode.YmodemTransfer);
        }

        public void YModemEnd()
        {
            SetMode(SerialPortMode.Command); // 结束传输后切换回命令模式
        }

        public bool SerialOpen(int timeout)
        {
            try
            {
                LogManager.Debug("=== Starting SerialOpen ===");
                
                // 检查串口是否已被占用
                bool isPortUsed = IsSerialPortUsed(portName);
                if (isPortUsed)
                {
                    LogManager.Error($"Serial port {portName} is already in use");
                    return false;
                }

                // 如果串口已经打开，先关闭它
                if (serialPort.IsOpen)
                {
                    LogManager.Debug("Serial port is already open, closing first...");
                    SerialClose();
                }

                // 检查当前状态并进行清理
                SerialPortMode currentMode = GetCurrentMode();
                LogManager.Debug($"Current mode before opening: {currentMode}");
                
                // 根据当前模式执行相应的清理操作
                switch (currentMode)
                {
                    case SerialPortMode.YmodemWait:
                    case SerialPortMode.YmodemTransfer:
                        LogManager.Debug("Cleaning up previous Ymodem operations...");
                        // 清空Ymodem数据队列
                        lock (_queueLock)
                        {
                            _ymodemDataQueue.Clear();
                            LogManager.Debug("Ymodem data queue cleared");
                        }
                        // 触发传输失败事件（如果有正在进行的传输）
                        DownloadResultEvent?.Invoke(false, new EventArgs());
                        LogManager.Debug("Previous Ymodem transfer cancelled");
                        break;
                        
                    case SerialPortMode.Command:
                        LogManager.Debug("Cleaning up previous command mode operations...");
                        // 清空命令缓冲区
                        lock (_commandBufferLock)
                        {
                            _commandBuffer.Clear();
                            LogManager.Debug("Command buffer cleared");
                        }
                        lock (_commandLinesLock)
                        {
                            _commandLines.Clear();
                            LogManager.Debug("Command lines cleared");
                        }
                        break;
                }

                // 强制重置到命令模式
                SetMode(SerialPortMode.Command);
                
                // 清理所有缓冲区和队列（确保完全清理）
                lock (_queueLock)
                {
                    _ymodemDataQueue.Clear();
                }
                lock (_commandBufferLock)
                {
                    _commandBuffer.Clear();
                }
                lock (_commandLinesLock)
                {
                    _commandLines.Clear();
                }
                
                // 配置串口参数
                serialPort.PortName = portName;
                serialPort.BaudRate = baudRate;
                
                // 确保串口参数正确配置
                serialPort.DataBits = 8;
                serialPort.StopBits = System.IO.Ports.StopBits.One;
                serialPort.Parity = System.IO.Ports.Parity.None;
                
                // 设置缓冲区大小
                serialPort.ReadBufferSize = 4096;
                serialPort.WriteBufferSize = 4096;

                // 订阅数据接收事件
                serialPort.DataReceived += SerialPort_DataReceived;
                
                // 设置结束符和超时
                serialPort.NewLine = "\r\n";
                serialPort.ReadTimeout = timeout;
                
                LogManager.Debug($"Opening serial port: {portName}, BaudRate: {baudRate}, Timeout: {timeout}ms");
                
                // 打开串口
                serialPort.Open();
                
                LogManager.Debug($"Serial port opened successfully. IsOpen: {serialPort.IsOpen}");
                
                // 清空串口缓冲区（清除可能存在的旧数据）
                if (serialPort.IsOpen)
                {
                    serialPort.DiscardInBuffer();
                    serialPort.DiscardOutBuffer();
                    LogManager.Debug("Serial port buffers cleared after opening");
                }
                
                // 测试事件是否正常工作
                LogManager.Debug("Serial port DataReceived event subscribed and ready");
                
                LogManager.Debug("=== SerialOpen completed successfully ===");
                return true;
            }
            catch (Exception ex)
            {
                LogManager.Error($"Failed to open serial port: {ex.Message}");
                LogManager.Error($"Stack trace: {ex.StackTrace}");
                
                // 确保在失败时清理状态
                try
                {
                    if (serialPort.IsOpen)
                    {
                        serialPort.Close();
                    }
                    SetMode(SerialPortMode.Command);
                }
                catch (Exception cleanupEx)
                {
                    LogManager.Error($"Error during cleanup after failed open: {cleanupEx.Message}");
                }
                
                return false;
            }
        }

        public void SendData(byte[] data)
        {
            // 发送数据
            if(serialPort != null && serialPort.IsOpen)
            {
                serialPort.Write(data, 0, data.Length);
                LogManager.Debug("Sent data: " + BitConverter.ToString(data, 0, data.Length));
            }
            else
            {
                LogManager.Error("Serial port is not open");
            }
        }
        public void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 添加事件触发日志
                LogManager.Debug("SerialPort_DataReceived event triggered!");
                
                SerialPortMode currentMode = GetCurrentMode();
                LogManager.Debug($"Current mode: {currentMode}");
                
                // 检查串口状态
                if (!serialPort.IsOpen)
                {
                    LogManager.Error("SerialPort_DataReceived: Serial port is not open!");
                    return;
                }
                
                int bytesToRead = serialPort.BytesToRead;
                LogManager.Debug($"Bytes to read: {bytesToRead}");
                
                if (bytesToRead == 0)
                {
                    LogManager.Debug("SerialPort_DataReceived: No bytes to read");
                    return;
                }
                
                // 读取所有可用数据
                byte[] buffer = new byte[bytesToRead];
                int bytesRead = serialPort.Read(buffer, 0, buffer.Length);
                LogManager.Debug($"Actually read {bytesRead} bytes");
                
                if (currentMode == SerialPortMode.YmodemWait || currentMode == SerialPortMode.YmodemTransfer)
                {
                    // Ymodem模式：将原始字节数据放入队列
                    lock (_queueLock)
                    {
                        for (int i = 0; i < bytesRead; i++)
                        {
                            _ymodemDataQueue.Enqueue(buffer[i]);
                        }
                    }
                    LogManager.Debug($"Ymodem mode: queued {bytesRead} bytes, total: {_ymodemDataQueue.Count}");
                    
                    // 记录接收到的数据（用于调试）
                    string hexData = BitConverter.ToString(buffer, 0, bytesRead);
                    LogManager.Debug($"Ymodem received bytes: {hexData}");
                }
                else if (currentMode == SerialPortMode.Command)
                {
                    // 命令模式：处理字符串数据，按\r\n分割
                    string receivedText = System.Text.Encoding.Default.GetString(buffer, 0, bytesRead);
                    LogManager.Debug($"Command mode received: {receivedText.Replace("\r", "\\r").Replace("\n", "\\n")}");
                    
                    lock (_commandBufferLock)
                    {
                        _commandBuffer.Append(receivedText);
                        
                        // 检查是否有完整的行（以\r\n结尾）
                        string bufferContent = _commandBuffer.ToString();
                        string[] lines = bufferContent.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                        
                        if (lines.Length > 1)
                        {
                            // 有完整的行
                            lock (_commandLinesLock)
                            {
                                for (int i = 0; i < lines.Length - 1; i++)
                                {
                                    if (!string.IsNullOrEmpty(lines[i]))
                                    {
                                        _commandLines.Add(lines[i]);
                                        LogManager.Debug($"Command line added: {lines[i]}");
                                    }
                                }
                            }
                            
                            // 保留最后一个不完整的部分
                            _commandBuffer.Clear();
                            _commandBuffer.Append(lines[lines.Length - 1]);
                        }
                    }
                    
                    Console.WriteLine(receivedText);
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"Error in SerialPort_DataReceived: {ex.Message}");
                LogManager.Error($"Stack trace: {ex.StackTrace}");
            }
        }



        private void GetSerialPortReadByte(ref byte temp)
        {
            // 在Ymodem模式下从队列读取数据
            if (GetCurrentMode() == SerialPortMode.YmodemWait || GetCurrentMode() == SerialPortMode.YmodemTransfer)
            {
                int timeoutMs = 30000; // 30秒超时
                int startTime = Environment.TickCount;
                
                while (Environment.TickCount - startTime < timeoutMs)
                {
                    lock (_queueLock)
                    {
                        if (_ymodemDataQueue.Count > 0)
                        {
                            temp = _ymodemDataQueue.Dequeue();
                            LogManager.Debug($"GetSerialPortReadByte from queue: {temp} (0x{temp:X2})");
                            return;
                        }
                    }
                    Thread.Sleep(10); // 短暂等待
                }
                
                // 超时处理
                LogManager.Debug("GetSerialPortReadByte timeout - no data in queue");
                temp = 0;
            }
            else
            {
                // 普通模式直接从串口读取
                temp = (byte)serialPort.ReadByte();
                LogManager.Debug($"GetSerialPortReadByte direct: {temp} (0x{temp:X2})");
            }
        }

        public void YmodemUploadFile(bool bFireware=true)
        {
            LogManager.Debug($"=== YmodemUploadFile started ===");
            LogManager.Debug($"Parameters: bFireware={bFireware}, Path={Path}");
            
            if(!serialPort.IsOpen)
            {
                LogManager.Error("Serial port is not open");
                return;
            }

            if(!File.Exists(Path))
            {
                LogManager.Error($"File does not exist: {Path}");
                return;
            }

            FileInfo fileInfo = new FileInfo(Path);
            LogManager.Debug($"File info: Size={fileInfo.Length} bytes, Name={fileInfo.Name}");

            // 切换到Ymodem等待模式
            LogManager.Debug("Switching to YmodemWait mode");
            SetMode(SerialPortMode.YmodemWait);
            /* control signals */
            const byte SOH = 1;  // Start of TeXt 
            const byte STX = 2;  // Start of TeXt 
            const byte EOT = 4;  // End Of Transmission
            const byte ACK = 6;  // Positive ACknowledgement
            const byte C = 67;   // capital letter C
            const byte NAK = 0x15; // 否定字符

            /* sizes */
            const int dataSize = 1024;
            const int crcSize = 2;

            /* THE PACKET: 1029 bytes */
            /* header: 3 bytes */
            // STX
            int packetNumber = 0;
            int invertedPacketNumber = 255;
            /* data: 1024 bytes */
            byte[] data = new byte[dataSize];
            /* footer: 2 bytes */
            byte[] CRC = new byte[crcSize];

            /* get the file */
            FileStream? fileStream = null;
            try
            {
                fileStream = new FileStream(@Path, FileMode.Open, FileAccess.Read);
            {
                LogManager.Debug("Waiting for 'C' character to begin transfer...");
                
                // 等待接收 'C' 字符
                byte receivedByte = 0;
                GetSerialPortReadByte(ref receivedByte);
                LogManager.Debug($"Received initial byte: {receivedByte} (0x{receivedByte:X2})");
                
                if (receivedByte != C)
                {
                    LogManager.Error($"Can't begin the transfer. Expected 'C' (67), received: {receivedByte} (0x{receivedByte:X2})");
                    SetMode(SerialPortMode.Command); // 切换回命令模式
                    DownloadResultEvent?.Invoke(false, new EventArgs());
                    return;
                }
                else 
                {
                    LogManager.Debug("Begin the transfer - received 'C' character successfully.");
                    SetMode(SerialPortMode.YmodemTransfer); // 切换到传输模式
                }

                byte temp = 0;
                // 固件模式下需要读取额外的3个字节
                if (bFireware)
                {
                    LogManager.Debug("Firmware mode: reading 3 additional bytes");
                    for (int i = 0; i < 3; i++)
                    {
                        GetSerialPortReadByte(ref temp);
                        LogManager.Debug($"Firmware byte {i+1}: {temp} (0x{temp:X2})");
                    }
                }

                LogManager.Debug("Sending initial packet...");
                sendYmodemInitialPacket(SOH, packetNumber, invertedPacketNumber, data, 128, Path, fileStream, CRC, crcSize);

                LogManager.Debug("Waiting for ACK after initial packet...");
                GetSerialPortReadByte(ref temp);
                LogManager.Debug($"Received after initial packet: {temp} (0x{temp:X2})");
                if (temp != ACK)
                {
                    LogManager.Error($"Can't send the initial packet. Expected ACK (6), received: {temp} (0x{temp:X2})");
                    DownloadResultEvent?.Invoke(false, new EventArgs());
                    return;
                }

                LogManager.Debug("Waiting for 'C' after initial ACK...");
                GetSerialPortReadByte(ref temp);
                LogManager.Debug($"Received after initial ACK: {temp} (0x{temp:X2})");
                if (temp != C)
                {
                    LogManager.Error($"Initial packet not acknowledged properly. Expected 'C' (67), received: {temp} (0x{temp:X2})");
                    DownloadResultEvent?.Invoke(false, new EventArgs());
                    return;
                }
                /* send packets with a cycle until we send the last byte */
                LogManager.Debug("Starting data packet transmission...");
                int fileReadCount=0;
                int totalPackets = (int)Math.Ceiling((double)fileStream.Length / dataSize);
                LogManager.Debug($"Total packets to send: {totalPackets}");
                
                do
                {
                    /* if this is the last packet fill the remaining bytes with 0 */
                    fileReadCount = fileStream.Read(data, 0, dataSize);
                    LogManager.Debug($"Read {fileReadCount} bytes from file");
                    if (fileReadCount == 0) break;
                    if (fileReadCount != dataSize)
                    {
                        LogManager.Debug($"Last packet: padding {dataSize - fileReadCount} bytes with zeros");
                        for (int i = fileReadCount; i < dataSize; i++)
                            data[i] = 0;
                    }

                    /* calculate packetNumber */
                    packetNumber++;
                    if (packetNumber > 255)
                        packetNumber -= 256;
                    LogManager.Debug($"Sending packet {packetNumber} of {totalPackets}");

                    /* calculate invertedPacketNumber */
                    invertedPacketNumber = 255 - packetNumber;

                    /* calculate CRC */
                    CRC = Crc16.ComputeChecksumBytes(data);
                    LogManager.Debug($"Packet CRC: {BitConverter.ToString(CRC)}");

                    /* send the packet */
                    sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
                    int progress = (int)((long)dataSize * packetNumber * 100 / fileStream.Length);
                    LogManager.Debug($"Transfer progress: {progress}%");
                    if (progress > 100) progress = 100;
                    if (progress !=0 )
                    {
                        string msg = System.IO.Path.GetFileName(Path) + "(" + progress.ToString() + "%)";
                        NowDownloadProgressEvent?.Invoke(msg, new EventArgs());
                    }

                    /* wait for ACK */
                    LogManager.Debug("Waiting for ACK after data packet...");
                    temp = (byte)serialPort.ReadByte();
                    LogManager.Debug($"Received after packet {packetNumber}: {temp} (0x{temp:X2})");
                    if (temp != ACK)
                    {
                        LogManager.Error($"Couldn't send packet {packetNumber}. Expected ACK (6), received: {temp} (0x{temp:X2})");
                        DownloadResultEvent?.Invoke(false, new EventArgs());
                        return;
                    }
                } while (dataSize == fileReadCount);
                
                LogManager.Debug("All data packets sent successfully");

                // 固件模式下需要读取额外的5个字节
                if (bFireware)
                {
                    LogManager.Debug("Firmware mode: reading 5 additional bytes before EOT");
                    for (int i = 0; i < 5; i++)
                    {
                        GetSerialPortReadByte(ref temp);
                        LogManager.Debug($"Firmware EOT byte {i+1}: {temp} (0x{temp:X2})");
                    }
                }
                
                /* send EOT (tell the downloader we are finished) */
                LogManager.Debug("Sending EOT (End of Transmission)...");
                SendData(new byte[] { EOT });
                
                LogManager.Debug("Waiting for response to EOT...");
                GetSerialPortReadByte(ref temp);
                LogManager.Debug($"Received after EOT: {temp} (0x{temp:X2})");

                /* get ACK (downloader acknowledge the EOT) */
                if (temp == NAK)
                {
                    LogManager.Debug("Received NAK, sending second EOT...");
                    SendData(new byte[] { EOT });
                    /* get ACK (downloader acknowledge the EOT) */
                    GetSerialPortReadByte(ref temp);
                    LogManager.Debug($"Received after second EOT: {temp} (0x{temp:X2})");
                    if (temp != ACK)
                    {
                        LogManager.Error($"Can't get ACK after second EOT. Expected ACK (6), received: {temp} (0x{temp:X2})");
                    }
                    else
                    {
                        LogManager.Debug("Second EOT acknowledged successfully.");
                    }
                }
                else if (temp != ACK)
                {
                    LogManager.Error($"Can't get ACK after first EOT. Expected ACK (6), received: {temp} (0x{temp:X2})");
                }
                else
                {
                    LogManager.Debug("First EOT acknowledged successfully.");
                }

                LogManager.Debug("Waiting for 'C' to send closing packet...");
                GetSerialPortReadByte(ref temp);
                LogManager.Debug($"Received before closing packet: {temp} (0x{temp:X2})");
                if (temp != C)
                {
                    LogManager.Error($"Can't send closing packet. Expected 'C' (67), received: {temp} (0x{temp:X2})");
                    DownloadResultEvent?.Invoke(false, new EventArgs());
                    return;
                }
                
                /* send closing packet */
                LogManager.Debug("Sending closing packet...");
                packetNumber = 0;
                invertedPacketNumber = 255;
                data = new byte[dataSize];
                CRC = new byte[crcSize];
                sendYmodemClosingPacket(SOH, packetNumber, invertedPacketNumber, data, 128, CRC, crcSize);

                bool bAck = false;
                // 固件模式下只需要读取1个字节，否则读取5个字节
                int len = bFireware ? 1 : 5;
                LogManager.Debug($"Waiting for final ACK (reading {len} bytes)...");
                for (int i = 0; i < len; i++)
                {
                    GetSerialPortReadByte(ref temp);
                    LogManager.Debug($"Final response byte {i+1}: {temp} (0x{temp:X2})");
                    if (temp == ACK)
                    {
                        bAck = true;
                        LogManager.Debug($"Final ACK received at byte {i+1}");
                    }
                }
                /* get ACK (downloader acknowledge the EOT) */
                if (!bAck)
                {
                    LogManager.Error("Can't complete the transfer - no final ACK received");
                    DownloadResultEvent?.Invoke(false, new EventArgs());
                    return;
                }
                else
                {
                    LogManager.Debug("Transfer completed successfully - final ACK received");
                }
            }
            }
            catch (Exception ex)
            {
                LogManager.Error($"File transfer failed: {ex.Message}");
                LogManager.Error($"Stack trace: {ex.StackTrace}");
                SetMode(SerialPortMode.Command); // 异常时切换回命令模式
                DownloadResultEvent?.Invoke(false, new EventArgs());
                return;
            }
            finally
            {
                fileStream?.Close();
                SetMode(SerialPortMode.Command); // 传输完成后切换回命令模式
                LogManager.Debug("Switched back to Command mode");
            }
            
            LogManager.Debug("=== File transfer completed successfully ===");
            DownloadResultEvent?.Invoke(true, new EventArgs());
            return;
        }

        private void sendYmodemInitialPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, string path, FileStream fileStream, byte[] CRC, int crcSize)
        {
            string fileName = System.IO.Path.GetFileName(path);
            string fileSize = fileStream.Length.ToString();
            LogManager.Debug("fileSize" + fileSize);
            /* add filename to data */
            int i;
            for (i = 0; i < fileName.Length && fileName.ToCharArray()[i] != 0; i++)
            {
                data[i] = (byte)fileName.ToCharArray()[i];
            }
            data[i] = 0;

            /* add filesize to data */
            int j;
            for (j = 0; j < fileSize.Length && fileSize.ToCharArray()[j] != 0; j++)
            {
                data[i + 1 + j] = (byte)fileSize.ToCharArray()[j];
            }
            data[i + 1 + j] = 0;

            /* fill the remaining data bytes with 0 */
            for (int k = i + 1 + j + 1; k < dataSize; k++)
            {
                data[k] = 0;
            }


            /* calculate CRC */
            CRC = Crc16.ComputeChecksumBytes(data,dataSize);
            LogManager.Debug($"CRC: {BitConverter.ToString(CRC, 0, CRC.Length)}");
            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }

        private void sendYmodemClosingPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, byte[] CRC, int crcSize)
        {
            /* calculate CRC */
            CRC = Crc16.ComputeChecksumBytes(data,dataSize);

            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }

        private void sendYmodemPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, byte[] CRC, int crcSize)
        {
            buffer.Clear();
            buffer.Add(STX);
            buffer.Add((byte)packetNumber);
            buffer.Add((byte)invertedPacketNumber);
            if (STX==1)//SOH
            {
                byte[] t = new byte[dataSize];
                Array.Copy(data, t, dataSize);
                buffer.AddRange(t);
            }
            else
            {
                buffer.AddRange(data);
            }
            buffer.AddRange(CRC);
            SendData(buffer.ToArray());
        }
    }
    public class Crc16
    {
        public static ushort ComputeChecksum(byte[] bytes, int start, int length)
        {
            var calculator = new CRC16(CRC16.Definition.XModem);
            var result = calculator.ComputeHash(bytes, start, length);
            ushort crc = BitConverter.ToUInt16(result, 0);
            return crc;
        }
        public static byte[] ComputeChecksumBytes(byte[] bytes)
        {
            ushort crc = ComputeChecksum(bytes, 0, bytes.Length);
            //return BitConverter.GetBytes(crc);
            return new byte[] { (byte)(crc >> 8), (byte)crc };
        }
        public static byte[] ComputeChecksumBytes(byte[] bytes, int len)
        {
            ushort crc = ComputeChecksum(bytes, 0, len);
            return new byte[] { (byte)(crc >> 8), (byte)crc };
        }
    }
}